\section{Пример вычисления адреса сети}

Как мы знаем, TCP/IP-адрес (IPv4) состоит из четырех чисел в пределах $0 \ldots 255$, т.е. 4 байта.

4 байта легко помещаются в 32-битную переменную, так что адрес хоста в IPv4, сетевая маска или адрес сети
могут быть 32-битными числами.

С точки зрения пользователя, маска сети определяется четырьмя числами в формате вроде \\
255.255.255.0,
но сетевые инженеры (сисадмины) используют более компактную нотацию (\ac{CIDR}),
вроде  \q{/8}, \q{/16}, итд.

Эта нотация просто определяет количество бит в сетевой маске, начиная с \ac{MSB}.

\small
\begin{center}
\begin{tabular}{ | l | l | l | l | l | l | }
\hline
\HeaderColor Маска & 
\HeaderColor Хосты & 
\HeaderColor Свободно &
\HeaderColor Сетевая маска &
\HeaderColor В шест.виде &
\HeaderColor \\
\hline
/30  & 4        & 2        & 255.255.255.252  & 0xfffffffc  & \\
\hline
/29  & 8        & 6        & 255.255.255.248  & 0xfffffff8  & \\
\hline
/28  & 16       & 14       & 255.255.255.240  & 0xfffffff0  & \\
\hline
/27  & 32       & 30       & 255.255.255.224  & 0xffffffe0  & \\
\hline
/26  & 64       & 62       & 255.255.255.192  & 0xffffffc0  & \\
\hline
/24  & 256      & 254      & 255.255.255.0    & 0xffffff00  & сеть класса C \\
\hline
/23  & 512      & 510      & 255.255.254.0    & 0xfffffe00  & \\
\hline
/22  & 1024     & 1022     & 255.255.252.0    & 0xfffffc00  & \\
\hline
/21  & 2048     & 2046     & 255.255.248.0    & 0xfffff800  & \\
\hline
/20  & 4096     & 4094     & 255.255.240.0    & 0xfffff000  & \\
\hline
/19  & 8192     & 8190     & 255.255.224.0    & 0xffffe000  & \\
\hline
/18  & 16384    & 16382    & 255.255.192.0    & 0xffffc000  & \\
\hline
/17  & 32768    & 32766    & 255.255.128.0    & 0xffff8000  & \\
\hline
/16  & 65536    & 65534    & 255.255.0.0      & 0xffff0000  & сеть класса B \\
\hline
/8   & 16777216 & 16777214 & 255.0.0.0        & 0xff000000  & сеть класса A \\
\hline
\end{tabular}
\end{center}
\normalsize

Вот простой пример, вычисляющий адрес сети используя сетевую маску и адрес хоста.

\lstinputlisting[style=customc]{\CURPATH/netmask.c}

\subsection{calc\_network\_address()}

Функция \TT{calc\_network\_address()} самая простая: 

она просто умножает (логически, используя \AND) адрес хоста на сетевую маску, в итоге давая адрес
сети.

\lstinputlisting[caption=\Optimizing MSVC 2012 /Ob0,numbers=left,style=customasmx86]{\CURPATH/calc_network_address_MSVC_2012_Ox.asm}

На строке 22 мы видим самую важную инструкцию \AND --- так вычисляется адрес сети.

\subsection{form\_IP()}

Функция \TT{form\_IP()} просто собирает все 4 байта в одно 32-битное значение.

Вот как это обычно происходит:

\begin{itemize}
\item Выделите переменную для возвращаемого значения. Обнулите её.

\item 
Возьмите четвертый (самый младший) байт, сложите его (логически, инструкцией \OR) с возвращаемым
значением. Оно содержит теперь 4-й байт.

\item Возьмите третий байт, сдвиньте его на 8 бит влево.
Получится значение в виде \TT{0x0000bb00}, где \TT{bb} это третий байт.
Сложите итоговое значение (логически, инструкцией \OR) с возвращаемым значением.
Возвращаемое значение пока что содержит \TT{0x000000aa}, так что логическое сложение
в итоге выдаст значение вида \TT{0x0000bbaa}.

\item 
Возьмите второй байт, сдвиньте его на 16 бит влево.
Вы получите значение вида \TT{0x00cc0000}, где \TT{cc} это второй байт.
Сложите (логически) результат и возвращаемое значение.
Выходное значение содержит пока что \TT{0x0000bbaa}, так что логическое сложение
в итоге выдаст значение вида \TT{0x00ccbbaa}.

\item 
Возьмите первый байт, сдвиньте его на 24 бита влево.
Вы получите значение вида \TT{0xdd000000}, где \TT{dd} это первый байт.
Сложите (логически) результат и выходное значение.
Выходное значение содержит пока что \TT{0x00ccbbaa}, так что сложение выдаст в итоге значение
вида \TT{0xddccbbaa}.

\end{itemize}

И вот как работает неоптимизирующий MSVC 2012:

\lstinputlisting[caption=\NonOptimizing MSVC 2012,style=customasmx86]{\CURPATH/form_IP_MSVC_2012_RU.asm}

Хотя, порядок операций другой, но, конечно, порядок роли не играет.

\Optimizing MSVC 2012 делает то же самое, но немного иначе:

\lstinputlisting[caption=\Optimizing MSVC 2012 /Ob0,style=customasmx86]{\CURPATH/form_IP_MSVC_2012_Ox_RU.asm}

Можно сказать, что каждый байт записывается в младшие 8 бит возвращаемого значения,
и затем возвращаемое значение сдвигается на один байт влево на каждом шаге.

Повторять 4 раза, для каждого байта.

\par
Вот и всё! 
К сожалению, наверное, нет способа делать это иначе.
Не существует более-менее популярных \ac{CPU} или \ac{ISA}, где имеется инструкция для сборки значения из бит или байт.
Обычно всё это делает сдвигами бит и логическим сложением (OR).

\subsection{print\_as\_IP()}

\TT{print\_as\_IP()} делает наоборот: расщепляет 32-битное значение на 4 байта.

Расщепление работает немного проще: просто сдвигайте входное значение на 24, 16, 8 или 0 бит,
берите биты с нулевого по седьмой (младший байт), вот и всё:

\lstinputlisting[caption=\NonOptimizing MSVC 2012,style=customasmx86]{\CURPATH/print_as_IP_MSVC_2012_RU.asm}

\Optimizing MSVC 2012 делает почти всё то же самое, только без ненужных перезагрузок входного значения:

\lstinputlisting[caption=\Optimizing MSVC 2012 /Ob0,style=customasmx86]{\CURPATH/print_as_IP_MSVC_2012_Ox.asm}

\subsection{form\_netmask() и set\_bit()}

\TT{form\_netmask()} делает сетевую маску из \ac{CIDR}-нотации.

Конечно, было бы куда эффективнее использовать здесь какую-то уже готовую таблицу, но мы рассматриваем
это именно так, сознательно, для демонстрации битовых сдвигов.
Мы также сделаем отдельную функцию \TT{set\_bit()}. 

Не очень хорошая идея выделять отдельную функцию для такой примитивной операции, но так будет проще понять,
как это всё работает.

\lstinputlisting[caption=\Optimizing MSVC 2012 /Ob0,style=customasmx86]{\CURPATH/form_netmask_MSVC_2012_Ox.asm}

\TT{set\_bit()} примитивна: просто сдвигает единицу на нужное количество бит, затем складывает (логически) с
входным значением \q{input}.
\TT{form\_netmask()} имеет цикл: он выставит столько бит (начиная с \ac{MSB}), 
сколько передано в аргументе \TT{netmask\_bits}.

\subsection{Итог}

Вот и всё!
Мы запускаем и видим:

\begin{lstlisting}
netmask=255.255.255.0
network address=10.1.2.0
netmask=255.0.0.0
network address=10.0.0.0
netmask=255.255.255.128
network address=10.1.2.0
netmask=255.255.255.192
network address=10.1.2.64
\end{lstlisting}
